package com.xiaolin.reflect;

import java.lang.reflect.*;
import java.util.ArrayList;

/**
 * @ClassName BasicTest
 * @Description 反射测试
 * @Detail     反射两个作用：
 *                  1、在程序运行时，能够获取到类的信息，包括属性和方法
 *                  2、在程序运行时，能够调用对象的属性和方法
 * @Author MyPC
 * @Date 2020/11/30
 * @Version 1.0
 */
public class BasicTest {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        String hello="hello";
        // 获取对象的Class对象
        Class<? extends String> aClass = hello.getClass();
        System.out.println(aClass);
        // 获取类的Class对象
        Class<String> stringClass = String.class;
        System.out.println(stringClass);
        // 获取类的全限定类名
        String className = aClass.getName();
        System.out.println(className);
        // 获取直接父类
        Class<?> superclass = aClass.getSuperclass();
        System.out.println(superclass);
        Student s1=new Student();
        Class<? extends Student> s1Class = s1.getClass();
        // 获取对象的所有构造方法
        Constructor<?>[] constructors = s1Class.getDeclaredConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }
        // 获取指定方法参数类型的构造器
        Constructor<? extends Student> declaredConstructor = s1Class.getDeclaredConstructor(String.class, int.class);
        // 获取访问修饰符
        System.out.println(Modifier.toString(declaredConstructor.getModifiers()));
        // 获取构造器方法参数类型列表
        for (Class<?> dClass : declaredConstructor.getParameterTypes()) {
            System.out.println(dClass);
        }
        // 利用构造器创建对象，实际上调用了对应的构造器
        declaredConstructor.newInstance("小林", 18);
        // 利用构造器调用私有构造器来创建对象
        Constructor<? extends Student> declaredConstructor2 = s1Class.getDeclaredConstructor(String.class);
        // 设置私有构造器可以访问
        declaredConstructor2.setAccessible(true);
        declaredConstructor2.newInstance("小林");
        //获取所有方法
        Method[] declaredMethods = s1Class.getDeclaredMethods();
        // 获取类的普通方法
        Method ageMethod = s1Class.getMethod("hello",int.class);
        System.out.println(ageMethod);
        // 获取类的方法参数集合
        for (Class<?> para : ageMethod.getParameterTypes()) {
            System.out.println(para);
        }
        // 调用方法
        ageMethod.invoke(s1,12);
        // 调用私有方法
        Method nameMethod = s1Class.getDeclaredMethod("hello", String.class);
        // 设置私有方法可以访问
        nameMethod.setAccessible(true);
        nameMethod.invoke(s1,"小林");
        // 获取所有属性
        Field[] declaredFields = s1Class.getDeclaredFields();
        // 操作普通属性
        Field name = s1Class.getDeclaredField("name");
        name.set(s1,"小花");
        // 操作私有属性
        Field age = s1Class.getDeclaredField("age");
        // 设置私有属性可以访问
        age.setAccessible(true);
        age.set(s1,12);
    }
}

class Student{
    public String name;
    private int age;
    public Student(){
        System.out.println("我是私有构造器");
    }
    private Student(String name){
        System.out.println("我是私有构造器");
    }
    public Student(String name,int age){
        this.name=name;
        this.age=age;
        System.out.println("名字："+this.name+"，年龄："+this.age);
    }
    public void hello(int age){
        System.out.println(age);
    }
    private void hello(String name){
        System.out.println(name);
    }
}
